package org.kazuhiko.rpg.objects;

import static java.lang.Math.cos;
import static java.lang.Math.sin;
import static java.lang.Math.toRadians;
import static org.lwjgl.opengl.GL11.glRotatef;
import static org.lwjgl.opengl.GL11.glTranslatef;

import org.kazuhiko.rpg.core.Drawable;
import org.kazuhiko.rpg.core.Face;
import org.kazuhiko.rpg.core.Physics;
import org.kazuhiko.rpg.core.Physics.GravityAcceleration;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.vector.Vector2f;
import org.lwjgl.util.vector.Vector3f;

public class Player extends Drawable
{
	private String name;
	
	public Player( String name, boolean autoload )
	{
		super( "res/models/cube_01.obj", autoload );
		this.name = name;
	}

	@Override
	public void tick()
	{
		if( !colliding() )
		{
			if( getFallingtime() <= 0 )
			{
				setStartFallingHeight( getPosition().y );
			}
			
			setPosition( new Vector3f( getPosition().x, getStartFallingHeight() - ( (float) ( getFallingtime() * Physics.getWeight( getMass(), GravityAcceleration.EARTH ) * 0.01 ) ), getPosition().z ) );
			
			setFallingTime( getFallingtime() + 1 );
		}
		
		if( getPosition().y < 0 )
		{
			setPosition( new Vector3f( getPosition().x, 0, getPosition().z ) );
		}
	}

	@Override
	public void render()
	{
		if( !isLoaded() )
		{
			load();
		}
		
		//Set position
		glTranslatef( getPosition().x, getPosition().y, getPosition().z );
		
		glRotatef( -getRotation().x, 1, 0, 0 );
		glRotatef( -getRotation().y, 0, 1, 0 );
		glRotatef( -getRotation().z, 0, 0, 1 );
		
		/*
		//Vertex handle
		glBindBuffer( GL_ARRAY_BUFFER, getVertexHandle() );
		glVertexPointer(3, GL_FLOAT, 0, 0L);
		
		//Normal handle
        glBindBuffer(GL_ARRAY_BUFFER, getNormalHandle() );
        glNormalPointer(GL_FLOAT, 0, 0L);
        
        //Enable states
        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_NORMAL_ARRAY);
        
        //Setting the color
        glColor4f( 0, 1, 0, 1f );
        //Setting the material
        glMaterialf(GL_FRONT, GL_SHININESS, 20f);
        //Drawing the model
        glDrawArrays(GL_TRIANGLES, 0, getModel().faces.size() * 3);
        
        //Disable states
        glDisableClientState(GL_VERTEX_ARRAY);
        glDisableClientState(GL_NORMAL_ARRAY);
        
        //Reset position
        glTranslatef( getPosition().x, getPosition().y, getPosition().z );
		
        /*
		glTranslatef( -getPosition().x + 0.1f, -getPosition().y - getHeight() - 0.1f, -getPosition().z );
		
		glColor4f( 1, 0, 0, 1 );
		
		glBegin( GL_LINES );
		{
			glVertex3f( -1.0f, -1.0f, 1.0f );
			glVertex3f( 1.0f, -1.0f, 1.0f );
			glVertex3f( 1.0f, 1.0f, 1.0f );
			glVertex3f( -1.0f, 1.0f, 1.0f );
			
			glVertex3f( -1.0f, -1.0f, -1.0f );
			glVertex3f( -1.0f, 1.0f, -1.0f );
			glVertex3f( 1.0f, 1.0f, -1.0f );
			glVertex3f( 1.0f, -1.0f, -1.0f );
			
			glVertex3f( -1.0f, 1.0f, -1.0f );
			glVertex3f( -1.0f, 1.0f, 1.0f );
			glVertex3f( 1.0f, 1.0f, 1.0f );
			glVertex3f( 1.0f, 1.0f, -1.0f );
			
			glVertex3f( -1.0f, -1.0f, -1.0f );
			glVertex3f( 1.0f, -1.0f, -1.0f );
			glVertex3f( 1.0f, -1.0f, 1.0f );
			glVertex3f( -1.0f, -1.0f, 1.0f );
			
			glVertex3f( 1.0f, -1.0f, -1.0f );
			glVertex3f( 1.0f, 1.0f, -1.0f );
			glVertex3f( 1.0f, 1.0f, 1.0f );
			glVertex3f( 1.0f, -1.0f, 1.0f );
			
			glVertex3f( -1.0f, -1.0f, -1.0f );
			glVertex3f( -1.0f, -1.0f, 1.0f );
			glVertex3f( -1.0f, 1.0f, 1.0f );
			glVertex3f( -1.0f, 1.0f, -1.0f );
		}
		glEnd();
		
		glTranslatef( getPosition().x - 0.1f, getPosition().y - getHeight() + 0.1f, getPosition().z );
		*/
		
		int currentTexture = 0;
		for( Face face : getModel().faces )
		{
			if( face.texture != currentTexture )
			{
				currentTexture = face.texture;
				GL11.glBindTexture( GL11.GL_TEXTURE_2D, currentTexture );
			}
			
			GL11.glColor3f( 1f, 1f, 1f );
			GL11.glBegin( GL11.GL_TRIANGLES );
			{
				Vector3f n1 = getModel().normals.get( ( int ) face.normal.x - 1 );
				GL11.glNormal3f( n1.x, n1.y, n1.z );
				
				Vector2f t1 = getModel().textVertices.get( ( int ) face.textures.x - 1 );
				GL11.glTexCoord2f( t1.x, t1.y );
				
				Vector3f v1 = getModel().vertices.get( ( int ) face.vertex.x - 1 );
				GL11.glVertex3f( v1.x, v1.y, v1.z );
				
				Vector3f n2 = getModel().normals.get( ( int ) face.normal.y - 1 );
				GL11.glNormal3f( n2.x, n2.y, n2.z );
				
				Vector2f t2 = getModel().textVertices.get( ( int ) face.textures.y - 1 );
				GL11.glTexCoord2f( t2.x, t2.y );
				
				Vector3f v2 = getModel().vertices.get( ( int ) face.vertex.y - 1 );
				GL11.glVertex3f( v2.x, v2.y, v2.z );
				
				Vector3f n3 = getModel().normals.get( ( int ) face.normal.z - 1 );
				GL11.glNormal3f( n3.x, n3.y, n3.z );
				
				Vector2f t3 = getModel().textVertices.get( ( int ) face.textures.z - 1 );
				GL11.glTexCoord2f( t3.x, t3.y );
				
				Vector3f v3 = getModel().vertices.get( ( int ) face.vertex.z - 1 );
				GL11.glVertex3f( v3.x, v3.y, v3.z );
			}
			GL11.glEnd();
		}
		
		glRotatef( -getRotation().x, 1, 0, 0 );
		glRotatef( -getRotation().y, 0, 1, 0 );
		glRotatef( -getRotation().z, 0, 0, 1 );
		
	}
	
	public String getName()
	{
		return name;
	}
	
	public void setName( String name )
	{
		this.name = name;
	}
	
	public void processMouse( float mouseSpeed, float maxLookUp, float maxLookDown )
	{	
		float mouseDX = Mouse.getDX() * mouseSpeed * 0.16f;
		
		if( Mouse.isGrabbed() )
		{			
			if( getRotation().y + mouseDX >= 360 )
			{
				setRotation( new Vector3f( getRotation().x, getRotation().y + mouseDX - 360, getRotation().z ) );
			}
			else if ( getRotation().y + mouseDX < 0 )
			{
				setRotation( new Vector3f( getRotation().x, 360 - getRotation().y + mouseDX, getRotation().z ) );
			}
			else
			{
				setRotation( new Vector3f( getRotation().x, getRotation().y + mouseDX, getRotation().z ) );
			}		
		}
	}
	
	public void processKeyboard( float delta, float speedX, float speedY, float speedZ )
	{
		if( delta <= 0 )
		{
			throw new IllegalArgumentException( "delta " + delta + " is 0 or smaller than 0" );
			//delta = 1;
		}
		
		boolean keyUp = Keyboard.isKeyDown( Keyboard.KEY_W );
		boolean keyDown = Keyboard.isKeyDown( Keyboard.KEY_S );
		boolean keyLeft = Keyboard.isKeyDown( Keyboard.KEY_A );
		boolean keyRight = Keyboard.isKeyDown( Keyboard.KEY_D );
		
		if( keyUp && keyRight && !keyLeft && !keyDown )
		{
			moveFromLook( speedX * delta * 0.003f, 0, -speedZ * delta * 0.003f );
		}
		if( keyUp && keyLeft && !keyRight && !keyDown )
		{
			moveFromLook( -speedX * delta * 0.003f, 0, -speedZ * delta * 0.003f );
		}
		if( keyUp && !keyLeft && !keyRight && !keyDown )
		{
			moveFromLook( 0, 0, -speedZ * delta * 0.003f );
		}
		
		if( keyDown && keyLeft && !keyRight && !keyUp )
		{
			moveFromLook( -speedX * delta * 0.003f, 0, speedZ * delta * 0.003f );
		}
		if( keyDown && keyRight && !keyLeft && !keyUp )
		{
			moveFromLook( speedX * delta * 0.003f, 0, speedZ * delta * 0.003f );
		}
		if( keyDown && !keyUp && !keyLeft && !keyRight )
		{
			moveFromLook( 0, 0, speedZ * delta * 0.003f );
		}
		
		if( keyLeft && !keyRight && !keyDown && !keyUp )
		{
			moveFromLook( -speedX * delta * 0.003f, 0, 0 );
		}
		
		if( keyRight && !keyLeft && !keyUp && !keyDown )
		{
			moveFromLook( speedX * delta * 0.003f, 0, 0 );
		}
	}
	
	public void moveFromLook( float dx, float dy, float dz )
	{
		float pitch = getRotation().x;
		float yaw = getRotation().y;
		
		float x = ( float ) ( ( getPosition().x + dx ) * ( float ) cos( toRadians( yaw - 90 ) ) + dz * cos ( toRadians( yaw ) ) );
		float y = ( float ) ( ( getPosition().y - dx ) * ( float ) sin( toRadians( yaw - 90 ) ) + dz * sin( toRadians( yaw ) ) );
		float z = ( float ) ( ( getPosition().z + dy ) * ( float ) sin( toRadians( pitch - 90 ) ) + dz * sin( toRadians( pitch ) ) );
		
		setPosition( new Vector3f( x, y, z ) );
	}
	
}
